#ifndef __SHELL_H__
#define __SHELL_H__

#include <map>
#include <string>
#include <vector>

#include "CPU.h"
#include "ShellStates.h"
#include "ExecutionContext.h"

using namespace std;

// interactive shell
class Shell
{
	public:
		// constructor
		// name: the name of this shell
		// core: filename of the core to load
		Shell(string name, string core);

		// destructor
		~Shell(void);

		// Gets the name
		string get_name();

		// Runs the shell
		// returns: the reason for terminating the Run
		ShellStates run();

		// Gets the Shell state
		ShellStates get_state() const;

	private:
		// constructor
		// cpu: the CPU this shell operates on
		// context: execution context
		// name: the name of this shell
		Shell(CPU* cpu, ExecutionContext* context, string name);

		// mapping of commands to functions with their help contents
		map < string, pair < void (Shell::*)(vector < string > *), string > > commandMap;

		// The execution context
		ExecutionContext* context;

		// the CPU this shell operates on
		CPU* cpu;

		// the shell's name
		string name;

		// The Shell State
		ShellStates state;

		// Manipulates breakpoints
		// args: the argument values to the command (minus the command)
		void breakpoint(vector<string>* args);

		// Clears the console
		// args: the argument values to the command (minus the command)
		void clear(vector<string>* args);

		// Creates a deep clone of the shell
		// args: the argument values to the command (minus the command)
		void clone(vector<string>* args);

		// Dumps the Cpu core
		// args: the argument values to the command (minus the command)
		void dump_core(vector<string>* args);

		// Exits the shell
		// args: the argument values to the command (minus the command)
		void exit(vector<string>* args);

		// reads a command from the shell prompt
		// args: the argument values to the command (minus the command)
		// returns: a pointer to the string containing the command (to be deleted)
		string get_parsed_command(vector<string>* args);

		// Shows the commands available
		// args: the argument values to the command (minus the command)
		void help(vector<string>* args);

		// initializes the command map
		void initialize_command_map();

		// Initializes the shell
		void initialize_shell(CPU* const cpu, ExecutionContext* const context);

		// Lists the breakpoints
		// os: ostream to write to
		void list_breakpoints(ostream& os) const;

		// Throws a request to list all shells
		// args: the argument values to the command (minus the command)
		void list_shells(vector<string>* args);

		// Loads the CPU state from the specified file
		// filename: the filename of the file to load
		void load_cpu_snapshot(const string& filename);

		// No-Op method
		// args: the argument values to the command (minus the command)
		void nop(vector<string>* args);

		// Unknown method
		// args: the argument values to the command (minus the command)
		void unknown_command(vector<string>* args);

		// Runs the program
		// args: the argument values to the command (minus the command)
		void run_program(vector<string>* args);

		// Saves the CPU state to the specified file
		// filename: the filename of the file to load
		void save_cpu_snapshot(const string& filename);

		// Sets the instruction pointer
		// args: the argument values to the command (minus the command)
		void set_instruction_pointer(vector<string>* args);

		// Shows the instruction at the specified address
		// address: address to show instruction for
		void show_instruction(unsigned int address) const;

		// Shows the next instruction
		// args: the argument values to the command (minus the command)
		void show_next_instruction(vector<string>* args);

		// Shows the CPU ticks
		// args: the argument values to the command (minus the command)
		void show_ticks(vector<string>* args);

		// Loads or saves a CPU snapshot
		// args: the argument values to the command (minus the command)
		void snapshot_cpu(vector<string>* args);

		// Executes the next instruction word
		// args: the argument values to the command (minus the command)
		void step(vector<string>* args);

		// suspends the shell and switches to the specified shell
		// args: the argument values to the command (minus the command)
		void switch_shells(vector<string>* args);

		// Executes the test procedure
		// args: the argument values to the command (minus the command)
		void test(vector<string>* args);
};
#endif
